﻿#include "file_log_appender.h"

#include <iomanip>
#include <sstream>
#include <filesystem>

#include <breaking/log/log_event.h>

namespace breaking
{
	file_log_appender::file_log_appender(const std::string& prefix, file_roll_type roll_type, size_t max_file_size)
	{
		m_prefix = prefix;
		m_roll_type = roll_type;
		m_max_file_size = max_file_size;
		m_roll_flag = false;
	}

	file_log_appender::~file_log_appender()
	{
	}

	bool file_log_appender::do_open()
	{
		if (!m_file_stream.is_open())
		{
			m_open_date = date(breaking::time::current_time());
			_ensure_directory_exists(_get_file_name());
			m_file_stream.open(_get_file_name().c_str(), std::ios::out | std::ios::app);
			return m_file_stream.is_open();
		}
		return true;
	}

	bool file_log_appender::do_append(const log_event& event)
	{
		date d(event.log_time);

		bool is_reopen = false;
		if (_check_reopen_by_date(d))
		{
			m_roll_flag = false;
			is_reopen = true;
		}
		else if (_check_reopen_by_size())
		{
			m_roll_flag = true;
			is_reopen = true;
		}

		if (is_reopen)
		{
			m_file_stream.close();
			m_open_date = d;
			_ensure_directory_exists(_get_file_name());
			m_file_stream.open(_get_file_name().c_str(), std::ios::out | std::ios::app);
		}

		m_file_stream << "[" << d.to_string() << "][" << get_log_priority_name(event.priority) << "]";
		m_file_stream << event.message << std::endl;
		m_file_stream.flush();

		return true;
	}

	void file_log_appender::do_close()
	{
		if (m_file_stream.is_open())
		{
			m_file_stream.close();
		}
	}

	std::string file_log_appender::_get_file_name() const
	{
		std::ostringstream stream;
		stream << m_prefix << "_" << std::setfill('0');
		switch (m_roll_type)
		{
		case file_roll_type::FILE_ROLL_HOUR:
		{
			stream << std::setw(4) << m_open_date.year()
				<< std::setw(2) << m_open_date.month()
				<< std::setw(2) << m_open_date.day()
				<< std::setw(2) << m_open_date.hour();

			break;
		}

		default:
		{
			stream << std::setw(4) << m_open_date.year()
				<< std::setw(2) << m_open_date.month()
				<< std::setw(2) << m_open_date.day();
			break;
		}
		}

		stream << ".log";

		if (m_roll_flag)
		{
			stream << ".bak."
				<< std::setw(2) << m_open_date.hour()
				<< std::setw(2) << m_open_date.minute()
				<< std::setw(2) << m_open_date.sec();
		}

		return stream.str();
	}

	bool file_log_appender::_check_reopen_by_date(const date& now) const
	{
		switch (m_roll_type)
		{
		case FILE_ROLL_HOUR:
		{
			return m_open_date.year() != now.year()
				|| m_open_date.month() != now.month()
				|| m_open_date.day() != now.day()
				|| m_open_date.hour() != now.hour();
		}
		case FILE_ROLL_DAY:
		{
			return m_open_date.year() != now.year()
				|| m_open_date.month() != now.month()
				|| m_open_date.day() != now.day();
		}
		case FILE_ROLL_MONTH:
		{
			return m_open_date.year() != now.year()
				|| m_open_date.month() != now.month();
			break;
		}
		default:
			break;
		}

		return false;
	}

	bool file_log_appender::_check_reopen_by_size()
	{
		if (m_max_file_size == 0) return false;

		m_file_stream.seekp(0, std::ios::end);
		return (size_t)m_file_stream.tellp() > m_max_file_size;
	}

	void file_log_appender::_ensure_directory_exists(const std::string& file_path)
	{
		// 获取文件所在的目录路径
		auto dir_path = std::filesystem::path(file_path).parent_path();

		// 如果目录不存在，则创建目录
		if (!std::filesystem::exists(dir_path))
		{
			std::filesystem::create_directories(dir_path);
		}
	}
}